package stage;

/**
 * Classe che implementa la struttura di controllo per la SpatialGrid.
 * Contiene tutte i GeometryContainer presenti anche nella SpatialGrid,
 * serve per rendere più semplice la ricerca dell'elemento da eliminare una volta
 * che la SpatialGrid fosse troppo piena.
 *
 * @author Matteo Cuccato
 * @author Nicola Girardi
 *
 */
public class ResultDistribution {

    // Variabili
    private ListaLinked[] res_dist;
    private int init_size = 20;

    /**
     * Metodo costruttore
     */
    public ResultDistribution() {
        res_dist = new ListaLinked[init_size];

        for (int i = 0; i < init_size; i++) {
            res_dist[i] = new ListaLinked();
        }
    }

    /**
     * Metodo che inserisce un elemento all'interno della struttura di controllo
     *
     * @param gc GeometryContainer da inserire
     * @exception NullPointerException Se la GeometryContainer è null
     */
    public void insert(GeometryContainer gc) throws NullPointerException {
        if (gc == null) {
            throw new NullPointerException("GeometryContainer null");
        }

        ListaLinked l_app = new ListaLinked();
        boolean trovato = false;
        GeometryContainer gc_app = new GeometryContainer();

        if (gc.getN_risultati() == 0) {
            l_app = res_dist[0];
            for (int i = 0; i < l_app.size(); i++) {
                gc_app = (GeometryContainer) l_app.get(i);
                if (gc_app.getId() == gc.getId()) {
                    trovato = true;
                }
            }
            if (!trovato) {
                l_app.insert(0, gc);
                res_dist[0] = l_app;
//                System.out.println("(insert) Inserito elemento : "+gc.getId()+", n_ris "+gc.getN_risultati());
            }
        } else {
            update(gc);
        }
    }

    /**
     * Metodo che modifica un elemento già presente nella struttura
     *
     * @param gc GeometryContainer da modificare
     * @exception NullPointerException Se la GeometryContainer è null
     */
    public void update(GeometryContainer gc) throws NullPointerException {
        if (gc == null) {
            throw new NullPointerException("GeometryContainer null");
        }

        if (gc.getN_risultati() > 0) {

            if (gc.getN_risultati() >= res_dist.length) {
                resize();
            }

            ListaLinked l_app = res_dist[gc.getN_risultati()];
            boolean trovato = false;
            GeometryContainer gc_app = new GeometryContainer();

            for (int i = 0; i < l_app.size(); i++) {
                gc_app = (GeometryContainer) l_app.get(i);
                if (gc_app.getId() == gc.getId()) {
                    trovato = true;
                }
            }
            if (!trovato) {
                l_app.insert(0, gc);
//                res_dist[gc.getN_risultati()] = null;
                res_dist[gc.getN_risultati()] = l_app;
//                System.out.println("(update) update elemento : "+gc.getId()+", riga "+gc.getN_risultati());
            }

            l_app = res_dist[gc.getN_risultati() - 1];
            for (int i = 0; i < l_app.size(); i++) {
                gc_app = (GeometryContainer) l_app.get(i);
                if (gc_app.getId() == gc.getId()) {
                    l_app.remove(i);
//                    System.out.println("(update) Remove elemento : "+gc.getId()+", riga "+(gc.getN_risultati() - 1));
                }
            }
            res_dist[gc.getN_risultati() - 1] = l_app;
//            System.out.println("(update) Inserito elemento : "+gc.getId()+", n_ris "+gc.getN_risultati());
        } else {

            if (gc.getN_risultati() == 0) {
                insert(gc);
            }
        }
    }

    /**
     * Trova il candidato, ovvero l'elemento che ha prodotto meno risultati al
     * tempo corrente, da eliminare se una SpatialGrid è troppo piena.
     *
     * @return GeometryContainer da eliminare all'interno della SpatialGrid
     */
    public GeometryContainer delete() {
        int cont = 0;
        boolean trovato = false;
        GeometryContainer gc = new GeometryContainer();
        ListaLinked l = new ListaLinked();

        while (!trovato && cont < res_dist.length) {
            l = res_dist[cont];
            if (!l.isEmpty()) {
                gc = (GeometryContainer) l.get(l.size() - 1);
                l.remove(l.size() - 1);
                trovato = true;
                System.out.println("(delete) Elimino l'elemento in pos: "+cont+", id: "+gc.getId());
            }
            cont++;
        }
        return gc;
    }

    /**
     * Metodo che ingrandisce l'array che rappresenta la struttura di controllo
     */
    private void resize() {
        ListaLinked[] l_app = new ListaLinked[res_dist.length + init_size];

        for (int i = 0; i < res_dist.length; i++) {
            l_app[i] = res_dist[i];
        }

        res_dist = l_app;
    }


    /**
     * Metodo che stampa il contenuto della ResultDistribution
     * 
     */
    public void printResultDistribution() {

        ListaLinked ll;
        GeometryContainer gc;

        System.out.println("Struttura ResultDistribution");
        System.out.println("...................................");
        for (int i = 0; i < res_dist.length; i++) {
            ll = res_dist[i];

//            System.out.println("(printResultDistribution) dimensione ll: "+ll.size());
            int cont = 0;
            
            System.out.println("N_risultati = "+i);

            if( ll.size() != 0 ){
                
                for (int j = 0; j < ll.size(); j++ ) {
                    gc = (GeometryContainer) ll.get(j);

                    System.out.println("- id: " + gc.getId() + ", n_ris: " + gc.getN_risultati());
                    
//                    gc = (GeometryContainer) ll.get(j);
                }
            }
        }
        System.out.println("...................................");
    }


}
